package com.ruoyi.backend.service.Impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.backend.mapper.RgbFusionMapper;
import com.ruoyi.backend.util.MinioUtil;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.backendEnum.SatelliteException;
import com.ruoyi.backend.dto.SatelliteDTO;
import com.ruoyi.backend.mapper.SatelliteMapper;
import com.ruoyi.backend.pojo.Satellite;
import com.ruoyi.backend.service.SatelliteService;
import com.ruoyi.integration.dto.RGBFusionSlicing;
import com.ruoyi.integration.service.InverseService;
import com.ruoyi.integration.service.MapRenderService;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.errors.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.util.*;

@Slf4j
@Service
public class SatelliteServiceImpl implements SatelliteService {

    @Autowired
    private SatelliteMapper satelliteMapper;

    @Autowired
    private RgbFusionMapper rgbFusionMapper;

    @Value("${minio-bucket.slices}")
    private String minioBucketName;

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioUtil minioUtil;

    @Autowired
    private MapRenderService mapRenderService;

    @Autowired
    private InverseService inverseService;


    // TODO：前端渲染服务两个接口调用之间的耗时问题需要解决
    @Override
    public void upload(SatelliteDTO satelliteDTO) throws IOException {
        /*
        1. 前端分片上传到MinIO,
        2. 调用MinIOn将分片上传的文件进行合并，
        3. 在Windows调用C+=算法进行RGB融合分片，直接存放到MinIO,供前端访问。
        4. 还是需要下载到本地，供生态参量反演算法调用
         */

        //TODO: MinIO存储桶作为融合切片文件存储器，将JSON字段[用于前端计算访问哪一个切片文件]需要保存到数据库中
        boolean exist = minioUtil.doesObjectExist(satelliteDTO.getMinioBucketName(), satelliteDTO.getMinioFileName());

        if (!exist) {
            throw new ServiceException(SatelliteException.SATELLITE_FILE_NOT_EXIST_IN_MINIO);
        }
        // 刷新rclone挂载的MinIO, 使得Windows上部署的C++可以调用MinIO中卫星文件
        inverseService.getRcloneMountMinIORefresh(satelliteDTO.getMinioBucketName());
        // 获取卫星类型对应需要融合波段信息
        String fusionBand = rgbFusionMapper.getFusionBand(satelliteDTO.getProductType());
        log.info("获取卫星类型对应需要融合波段信息: {}", fusionBand);
        // 调用封装的C++地图渲染服务进行RGB融合分片发布
        JSONObject jsonObject = mapRenderService.multisBandsTif2png(new RGBFusionSlicing(satelliteDTO.getMinioBucketName(), satelliteDTO.getMinioFileName(), fusionBand));
        // 判断服务调用是否成功并返回响应
        if (jsonObject == null || jsonObject.isEmpty()){
            throw new ServiceException(SatelliteException.SATELLITE_FILE_RGB_FUSION_SLICING_FAIL);
        }
        satelliteDTO.setSatelliteId(generateSatelliteId(satelliteDTO.getMineId(), satelliteDTO.getProductType(), satelliteDTO.getDataSource(), satelliteDTO.getBandSituation()));
        // 将卫星文件相关信息上传数据库持久化存储
        satelliteMapper.upload(satelliteDTO);
        // 刷新rclone挂载的MinIO, 使得前端访问MinIO可以立即看到新增的卫星RGB融合切片文件
        inverseService.getRcloneMountMinIORefresh(minioBucketName);

    }

    @Override
    public void update(Satellite satellite) {
        if (satelliteMapper.getCountSatelliteId(satellite.getSatelliteId()) == 0) {
            throw new ServiceException(SatelliteException.SATELLITE_DATA_NOT_EXIST);
        }
        satelliteMapper.update(satellite);
    }

    @Override
    public List<Satellite> search(String mineId, String productType, String dataSource, String productName, String satelliteType, LocalDate startTime, LocalDate endTime, String productLevel) {
        List<Satellite> satelliteList = satelliteMapper.search(mineId, productType, dataSource, productName, satelliteType, startTime, endTime, productLevel);
//        if (satelliteList.isEmpty()){
//            throw new ServiceException(SatelliteException.SATELLITE_DATA_NOT_FOUND);
//        }
        return satelliteList;
    }

    @Override
    public void delete(String id) {
        if (satelliteMapper.getCountSatelliteId(id) == 0) {
            throw new ServiceException(SatelliteException.SATELLITE_DATA_NOT_EXIST);
        }
        //先查询要删除的卫星影像数据
        Satellite satellite = satelliteMapper.findById(id);
        if (satellite != null) {
            //删除minio文件
            String minioFileName = satellite.getMinioFileName();
            boolean removed = minioUtil.removeFile(minioBucketName, minioFileName);
            if (!removed) {
                throw new ServiceException("删除 Minio 文件失败: " + minioFileName);
            }
        }
        satelliteMapper.delete(id);
    }

    @Override
    public String generateSatelliteId(String mine_id, String product_type, String data_source, String band_situation) {

        String prefix = mine_id + product_type + data_source;

        List<Satellite> lastRecord = satelliteMapper.findBySatelliteIdPrefix(prefix);
        String newIdSuffix = "00001";

        if (!lastRecord.isEmpty()) {
            String lastId = lastRecord.get(0).getSatelliteId();
            String lastIdSuffix = lastId.substring(lastId.length() - 5);
            newIdSuffix = String.format("%05d", Integer.parseInt(lastIdSuffix) + 1);
        }
        System.out.println(prefix + newIdSuffix);
        return prefix + newIdSuffix;
    }

    @Override
    public Object getMeta(String minioObjectName){

        minioObjectName = minioObjectName + File.separator + "meta.json";

        try (InputStream stream = minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(minioBucketName)
                        .object(minioObjectName)
                        .build()
        )) {
            // 2. 使用 IOUtils 简化读取
            String content = IOUtils.toString(stream, StandardCharsets.UTF_8);
            log.trace("读取到的原始内容: {}", content);

            // 3. 使用 Jackson 解析为 Map
            return JSONUtil.parseObj(content);

        } catch (MinioException e) {
            log.error("MinIO 服务异常（异常类型: {}）: bucket=rgb-fusion-slices, object={}, message={}",
                    e.getClass().getSimpleName(), minioObjectName, e.getMessage(), e);
            throw new RuntimeException("MinIO 服务异常: " + e.getMessage() + " [文件: " + minioObjectName + "]", e);
        } catch (java.security.InvalidKeyException | java.security.NoSuchAlgorithmException e) {
            log.error("MinIO 客户端配置错误: {}", e.getMessage(), e);
            throw new RuntimeException("MinIO 客户端配置错误，请检查密钥或算法设置 [文件: " + minioObjectName + "]", e);
        } catch (IOException e) {
            log.error("读取或解析文件失败: bucket=rgb-fusion-slices, object={}", minioObjectName, e);
            throw new RuntimeException("读取或解析 meta.json 失败: " + e.getMessage() + " [文件: " + minioObjectName + "]", e);
        } catch (Exception e) {
            log.error("未知异常: bucket=rgb-fusion-slices, object={}", minioObjectName, e);
            throw new RuntimeException("读取 meta.json 时发生未知错误 [文件: " + minioObjectName + "]", e);
        }

    }
}
